import Koa from 'koa';
import 'dotenv/config';
import redis from './utils/redis.js'
import sequelize from './config/db.js';
import cors from '@koa/cors';
import bodyParser from 'koa-bodyparser';
import { initRegKeys, initJWTKeys } from './utils/crypto.js';
import fs from "fs"
import path from "path"
import { fileURLToPath, pathToFileURL } from 'url'
import Visit from './models/Visit.js';
import ArticleStat from './models/ArticleStat.js';
import ArticleView from './models/ArticleView.js';
// 获取当前文件的路径
const __filename = fileURLToPath(import.meta.url);
// 获取当前文件的目录路径
const __dirname = path.dirname(__filename);
const app = new Koa();

// 中间件
app.use(bodyParser({
  enableTypes: ['json'],       // 仅处理 JSON
  strict: true                 // 严格模式（拒绝非对象/数组）
}));
app.use(cors());
// 防止 XSS
app.use(async (ctx, next) => {
  ctx.set('Content-Security-Policy', "default-src 'self'");
  await next();
});

// 动态导入并挂载路由 
const routesPath = path.join(__dirname, 'routes');
fs.readdirSync(routesPath).forEach(async (file) => {
  if (file.endsWith('.js')) {
    const filePath = path.join(routesPath, file);
    const fileUrl = pathToFileURL(filePath).href; // 转换为 file:// URL
    const module = await import(fileUrl); // 使用 file:// URL 导入
    const router = module.default;
    app.use(router.routes());
    app.use(router.allowedMethods());
  }
});

// 初始化数据库
sequelize.sync({ alter: true })
  .then(() => console.log('MySQL connected'))
  .catch(err => console.error('MySQL error:', err));


// 4. 应用退出时优雅关闭
process.on('SIGINT', async () => {
  await redis.disconnect()
  process.exit(0)
})
await initRegKeys()
await initJWTKeys()

app.use(async (ctx, next) => {

  const isArticleView = ctx.path.startsWith('/api/article/') && ctx.method === 'GET';

  // 非文章浏览请求直接跳过
  if (!isArticleView) {
    await next();
    return;
  }
  if (!ctx.query.userId) {
    ctx.body = {
      code: 'USER_ERROR',
      message: '没有找到当前用户,请登录后在看'
    }
    await next();
    return;
  }
  // 手动提取 id
  const pathSegments = ctx.path.split('/'); // 分割路径
  const articleId = pathSegments[pathSegments.length - 1]; // 获取最后一段
  // 提取关键信息
  const userId = ctx.query.userId;
  const ip = ctx.ip;
  const userAgent = ctx.headers['user-agent'];

  // 生成复合缓存键
  const cacheKey = `article_view:${articleId}:${userId}`;

  try {
    // 检查 Redis 是否存在记录
    const exists = await redis.exists(cacheKey);
    if (exists) {
      await next();
      return;
    }

    // 使用事务处理统计更新
    await sequelize.transaction(async t => {
      try {
        // 检查记录是否存在
        const [stat, created] = await ArticleStat.findOrCreate({
          where: { article_id: articleId },
          defaults: { view_count: 0, last_viewed_at: new Date() },
          transaction: t
        });

        // 更新记录
        await stat.update({
          view_count: sequelize.literal('view_count + 1'),
          last_viewed_at: new Date()
        }, {
          where: { article_id: articleId },
          transaction: t
        });

        // 插入详细记录
        await ArticleView.create({
          article_id: articleId,
          user_id: userId,
          ip,
          user_agent: userAgent
        }, { transaction: t });

        // 提交事务
        // await t.commit();
      } catch (error) {
        // 回滚事务
        // await t.rollback();
        console.error('操作失败:', error);
      }
    });
    console.log(8888888888)
    // 设置 Redis 缓存（10分钟过期）
    await redis.set(cacheKey, '1', 300);
  } catch (error) {
    console.error('文章统计失败:', error);
  }

  await next();
});
// 统计访问人数的中间件
app.use(async (ctx, next) => {
  const ip = ctx.ip; // 获取 IP 地址
  const userAgent = ctx.headers['user-agent']; // 获取浏览器信息
  const url = ctx.url; // 获取访问的 URL
  const referrer = ctx.headers['referer']; // 获取来源页面
  const visitedAt = new Date(); // 获取访问时间
  // 生成 Redis 缓存的 Key
  const cacheKey = `visit:${ip}:${url}`;
  // 检查 Redis 中是否存在该 Key
  const exists = await redis.exists(cacheKey);


  // 如果不存在，则保存记录并设置缓存
  if (exists || url.startsWith('/api/posts')) {
    await next();
    return
  }
  try {
    // 插入访问记录
    await Visit.create({
      ip,
      user_agent: userAgent,
      visited_at: visitedAt,
      url,
      referrer,
    });

    // 将记录写入 Redis，设置 10 分钟过期时间
    await redis.set(cacheKey, '1', 600);
    console.log('访问记录已保存');
  } catch (error) {
    console.error('保存访问记录失败：', error);
  }

  await next(); // 继续处理请求
});


app.listen(3000, () => {
  console.log('Server running on port 3000');
});

